package service

import (
	"fmt"
	"os"
	"path"
	"strings"
	"time"

	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
)

type SshStruct struct {
	SshClient *ssh.Client
}

func (that *SshStruct) Shell(cmd string) (string, any) {
	sshSession, err := that.SshClient.NewSession()
	if err != nil {
		return "", "打开会话失败" + err.Error()
	}
	result, _ := sshSession.CombinedOutput(cmd)
	defer sshSession.Close()
	return strings.TrimSpace(string(result)), nil
}

func (that *SshStruct) Conn(AuthInfo map[string]any, Ip string) (bool, string) {

	options := map[string]any{
		"type": "other",
		"port": 22,
	}
	for key, value := range AuthInfo {
		options[key] = value
	}

	SshAuth := make([]ssh.AuthMethod, 0)
	switch options["type"] {
	case "password":
		SshAuth = append(SshAuth, ssh.Password(fmt.Sprintf("%s", options["password"])))
	case "private":
		private_key := []byte(fmt.Sprintf("%v", options["private_key"]))
		signer, err := ssh.ParsePrivateKey(private_key)
		if err != nil {
			return false, "密钥打开失败" + err.Error()
		}
		SshAuth = append(SshAuth, ssh.PublicKeys(signer))
	default:
		return false, "登录方式不存在"
	}

	SshClientConfig := &ssh.ClientConfig{
		User:            fmt.Sprintf("%s", options["name"]),
		Auth:            SshAuth,
		Timeout:         30 * time.Second,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}
	addr := fmt.Sprintf("%s:%d", Ip, options["port"])

	var err error
	that.SshClient, err = ssh.Dial("tcp", addr, SshClientConfig)
	if err != nil {
		return false, "服务器ssh登录失败" + err.Error()
	}
	return true, "连接成功"
}

func UploadFile(sshClient *ssh.Client, localFile, remotePath string) (bool, any) {

	file, err := os.Open(localFile)
	if nil != err {
		return false, "上传时:打开本地文件失败" + err.Error()
	}
	defer file.Close()
	sftpClient, err := sftp.NewClient(sshClient)
	if nil != err {
		return false, "上传时:创建sftp连接失败" + err.Error()
	}
	remoteFileName := path.Base(localFile)
	remoteFlie := path.Join(strings.TrimSpace(remotePath), remoteFileName)

	if a, err := sftpClient.Stat(remoteFlie); err != nil {
		if os.IsExist(err) {
			if b, _ := file.Stat(); b.Size() == a.Size() {
				return true, "上传成功"
			}
		}
	} else if err == nil {
		if b, _ := file.Stat(); b.Size() == a.Size() {
			return true, "上传成功"
		}
	}

	ftpFile, err := sftpClient.Create(remoteFlie)
	if nil != err {
		return false, "上传时:创建远程目录失败" + err.Error()
	}

	if _, err := ftpFile.ReadFrom(file); nil != err {
		return false, "上传时:读本地写入远程文件失败" + err.Error()
	}

	defer ftpFile.Close()
	return true, "上传成功"
}
